<?php

/**
 * 字符验证 工具
 * 
  email    => 是否为有效的email地址
  numeric  => 是否为全是数字的字符串(可以是 "0" 开头的数字串)
  qq       => 腾讯qq号
  idcard   => 身份证号码
  china    => 是否为中文
  onchina  => 是否含有中文
  zip      => 邮政编码
  phone    => 固定电话(区号可有可无)
  mobile   => 手机号码
  mobilephone => 手机和固定电话
  url      => url地址
  account  => 用户帐号(字母开头，由字母数字下划线组成，6-20字节)
  ip       => ip地址
  word     => 合法字符(字母，数字，下划线)
 */
class Verifier {

    //定义的正则表达式
    static private $_regExp = array(
        'email' => '/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([_a-z0-9]+\.)+[a-z]{2,5}$/',
        'numeric' => '/^[0-9]+$/',
        'zip' => '/^[1-9]\d{5}$/',
        'phone' => '/^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/',
        'mobile' => '/^((\(\d{2,3}\))|(\d{3}\-))?1[3|4|5|7|8|9]\d{9}$/',
        'mobilephone' => '/(^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,12}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}1[3|4|5|7|8|9][0-9]{9}$)/',
        'qq' => '/^[1-9]*[1-9][0-9]*$/',
        'china' => '/^[\x7f-\xff]+$/',
        'onchina' => '/[\x7f-\xff]/',
        'idcard' => '/(^\d{15}$)|(^\d{17}([0-9]|X)$)/',
        'url' => '/[a-zA-Z]+:\/\/[^\s]*/',
        'account' => '/^[a-zA-Z0-9][a-zA-Z0-9_]{3,19}$/',
        'ip' => '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/',
        'word' => '/[a-zA-Z0-9_]$/',
        'time' => '/\d{2}:\d{2}/',
    );

    /**
     * 检测字符串
     *
     * @param string $key :检测的类型，如:"email" 或者是自定义的正则表达式,如:"/^a/"
     * @param string $string :要检测的字符串
     * 
     * @return boolean
     */
    static public function valid($key, $string) {
        // 是定义的正则表达式
        if (array_key_exists($key, self::$_regExp)) {
            return preg_match(self::$_regExp[$key], $string);
        } else {
            // 直接正则来判断
            return preg_match($key, $string);
        }
    }

    static public function validIDCard($vStr) {
        $vCity = array(
            '11', '12', '13', '14', '15', '21', '22',
            '23', '31', '32', '33', '34', '35', '36',
            '37', '41', '42', '43', '44', '45', '46',
            '50', '51', '52', '53', '54', '61', '62',
            '63', '64', '65', '71', '81', '82', '91'
        );

        if (!preg_match('/^([\d]{17}[xX\d]|[\d]{15})$/', $vStr))
            return false;

        if (!in_array(substr($vStr, 0, 2), $vCity))
            return false;

        $vStr = preg_replace('/[xX]$/i', 'a', $vStr);
        $vLength = strlen($vStr);

        if ($vLength == 18) {
            $vBirthday = substr($vStr, 6, 4) . '-' . substr($vStr, 10, 2) . '-' . substr($vStr, 12, 2);
        } else {
            $vBirthday = '19' . substr($vStr, 6, 2) . '-' . substr($vStr, 8, 2) . '-' . substr($vStr, 10, 2);
        }

        if (date('Y-m-d', strtotime($vBirthday)) != $vBirthday)
            return false;
        if ($vLength == 18) {
            $vSum = 0;

            for ($i = 17; $i >= 0; $i--) {
                $vSubStr = substr($vStr, 17 - $i, 1);
                $vSum += (pow(2, $i) % 11) * (($vSubStr == 'a') ? 10 : intval($vSubStr, 11));
            }

            if ($vSum % 11 != 1)
                return false;
        }

        return true;
    }

}
